;; This Source Code Form is subject to the terms of the Mozilla Public
;; License, v. 2.0. If a copy of the MPL was not distributed with this
;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
;;
;; Copyright (c) KALEIDOS INC

(ns app.main.ui.workspace.sidebar.options.menus.stroke
  (:require-macros [app.main.style :as stl])
  (:require
   [app.common.data :as d]
   [app.common.data.macros :as dm]
   [app.common.types.stroke :as cts]
   [app.main.data.workspace :as udw]
   [app.main.data.workspace.colors :as dc]
   [app.main.data.workspace.tokens.application :as dwta]
   [app.main.store :as st]
   [app.main.ui.components.title-bar :refer [title-bar*]]
   [app.main.ui.ds.buttons.icon-button :refer [icon-button*]]
   [app.main.ui.ds.foundations.assets.icon :as i]
   [app.main.ui.hooks :as h]
   [app.main.ui.workspace.sidebar.options.rows.stroke-row :refer [stroke-row*]]
   [app.util.dom :as dom]
   [app.util.i18n :as i18n :refer [tr]]
   [cuerdas.core :as str]
   [rumext.v2 :as mf]))

(def stroke-attrs
  [:strokes
   :stroke-style
   :stroke-alignment
   :stroke-width
   :stroke-color
   :stroke-color-ref-id
   :stroke-color-ref-file
   :stroke-opacity
   :stroke-color-gradient
   :stroke-cap-start
   :stroke-cap-end])

(mf/defc stroke-menu
  {::mf/wrap [#(mf/memo' % (mf/check-props ["ids" "values" "type" "show-caps" "applied-tokens"]))]}
  [{:keys [ids type values show-caps disable-stroke-style applied-tokens shapes objects] :as props}]
  (let [label (case type
                :multiple (tr "workspace.options.selection-stroke")
                :group (tr "workspace.options.group-stroke")
                (tr "labels.stroke"))

        state*          (mf/use-state true)
        open?           (deref state*)

        toggle-content  (mf/use-fn #(swap! state* not))
        open-content    (mf/use-fn #(reset! state* true))

        strokes         (:strokes values)
        has-strokes?    (or (= :multiple strokes) (some? (seq strokes)))


        on-color-change
        (mf/use-fn
         (mf/deps ids)
         (fn [index color]
           (st/emit! (udw/trigger-bounding-box-cloaking ids))
           (st/emit! (dc/change-stroke-color ids color index))))


        on-remove
        (mf/use-fn
         (mf/deps ids)
         (fn [index]
           (st/emit! (udw/trigger-bounding-box-cloaking ids))
           (st/emit! (dc/remove-stroke ids index))))

        handle-remove-all
        (mf/use-fn
         (mf/deps ids)
         (fn [_]
           (st/emit! (udw/trigger-bounding-box-cloaking ids))
           (st/emit! (dc/remove-all-strokes ids))))

        on-color-detach
        (mf/use-fn
         (mf/deps ids)
         (fn [index color]
           (st/emit! (udw/trigger-bounding-box-cloaking ids))
           (let [color (-> color
                           (dissoc :ref-id :ref-file))]
             (st/emit! (dc/change-stroke-color ids color index)))))

        handle-reorder
        (mf/use-fn
         (mf/deps ids)
         (fn [from-pos to-space-between-pos]
           (st/emit! (udw/trigger-bounding-box-cloaking ids))
           (st/emit! (dc/reorder-strokes ids from-pos to-space-between-pos))))

        on-stroke-style-change
        (mf/use-fn
         (mf/deps ids)
         (fn [index value]
           (st/emit! (udw/trigger-bounding-box-cloaking ids))
           (st/emit! (dc/change-stroke-attrs ids {:stroke-style value} index))))

        on-stroke-alignment-change
        (fn [index value]
          (when-not (str/empty? value)
            (st/emit! (udw/trigger-bounding-box-cloaking ids))
            (st/emit! (dc/change-stroke-attrs ids {:stroke-alignment value} index))))

        on-stroke-width-change
        (fn [index value]
          (when-not (str/empty? value)
            (st/emit! (udw/trigger-bounding-box-cloaking ids))
            (st/emit! (dc/change-stroke-attrs ids {:stroke-width value} index))))

        open-caps-select
        (fn [caps-state]
          (fn [event]
            (let [window-size (dom/get-window-size)

                  target (dom/get-current-target event)
                  rect   (dom/get-bounding-rect target)

                  top (if (< (+ (:bottom rect) 320) (:height window-size))
                        (+ (:bottom rect) 5)
                        (- (:height window-size) 325))

                  left (if (< (+ (:left rect) 200) (:width window-size))
                         (:left rect)
                         (- (:width window-size) 205))]
              (swap! caps-state assoc :open? true
                     :left left
                     :top top))))

        close-caps-select
        (fn [caps-state]
          (fn [_]
            (swap! caps-state assoc :open? false)))

        on-stroke-cap-start-change
        (fn [index value]
          (st/emit! (udw/trigger-bounding-box-cloaking ids))
          (st/emit! (dc/change-stroke-attrs ids {:stroke-cap-start value} index)))

        on-stroke-cap-end-change
        (fn [index value]
          (st/emit! (udw/trigger-bounding-box-cloaking ids))
          (st/emit! (dc/change-stroke-attrs ids {:stroke-cap-end value} index)))

        on-stroke-cap-switch
        (fn [index]
          (let [stroke-cap-start (get-in values [:strokes index :stroke-cap-start])
                stroke-cap-end   (get-in values [:strokes index :stroke-cap-end])]
            (when (and (not= stroke-cap-start :multiple)
                       (not= stroke-cap-end :multiple))
              (st/emit! (udw/trigger-bounding-box-cloaking ids))
              (st/emit! (dc/change-stroke-attrs ids {:stroke-cap-start stroke-cap-end
                                                     :stroke-cap-end stroke-cap-start} index)))))
        on-add-stroke
        (fn [_]
          (st/emit! (udw/trigger-bounding-box-cloaking ids))
          (st/emit! (dc/add-stroke ids cts/default-stroke))
          (when (not (some? (seq strokes))) (open-content)))

        disable-drag    (mf/use-state false)

        on-focus (fn [_]
                   (reset! disable-drag true))

        on-blur (fn [_]
                  (reset! disable-drag false))
        on-detach-token
        (mf/use-fn
         (mf/deps ids)
         (fn [token attrs]
           (st/emit! (dwta/unapply-token {:attributes attrs
                                          :token token
                                          :shape-ids ids}))))]

    [:div {:class (stl/css :stroke-section)}
     [:div {:class (stl/css :stroke-title)}
      [:> title-bar* {:collapsable  has-strokes?
                      :collapsed    (not open?)
                      :on-collapsed toggle-content
                      :title        label
                      :class        (stl/css-case :stroke-title-bar (not has-strokes?))}
       (when (not (= :multiple strokes))
         [:> icon-button* {:variant "ghost"
                           :aria-label (tr "workspace.options.stroke.add-stroke")
                           :on-click on-add-stroke
                           :icon i/add
                           :data-testid "add-stroke"}])]]
     (when open?
       [:div {:class (stl/css-case :stroke-content true
                                   :stroke-content-empty (not has-strokes?))}
        (cond
          (= :multiple strokes)
          [:div {:class (stl/css :stroke-multiple)}
           [:div {:class (stl/css :stroke-multiple-label)}
            (tr "settings.multiple")]
           [:> icon-button* {:variant "ghost"
                             :aria-label (tr "workspace.options.stroke.remove-stroke")
                             :on-click handle-remove-all
                             :icon i/remove}]]
          (seq strokes)
          [:> h/sortable-container* {}
           (for [[index value] (d/enumerate (:strokes values []))]
             [:> stroke-row* {:key (dm/str "stroke-" index)
                              :stroke value
                              :title (tr "workspace.options.stroke-color")
                              :index index
                              :shapes shapes
                              :objects objects
                              :show-caps show-caps
                              :on-color-change on-color-change
                              :on-color-detach on-color-detach
                              :on-stroke-width-change on-stroke-width-change
                              :on-stroke-style-change on-stroke-style-change
                              :on-stroke-alignment-change on-stroke-alignment-change
                              :open-caps-select open-caps-select
                              :close-caps-select close-caps-select
                              :on-stroke-cap-start-change on-stroke-cap-start-change
                              :on-stroke-cap-end-change on-stroke-cap-end-change
                              :on-stroke-cap-switch on-stroke-cap-switch
                              :applied-tokens applied-tokens
                              :on-detach-token on-detach-token
                              :on-remove on-remove
                              :on-reorder handle-reorder
                              :disable-drag disable-drag
                              :on-focus on-focus
                              :select-on-focus (not @disable-drag)
                              :on-blur on-blur
                              :ids ids
                              :disable-stroke-style disable-stroke-style}])])])]))
